<?php
/**
 * Workerman消息事件中，需要统一挂载的公共组件
*/

namespace houze;
use houze\SystemTips;
use houze\Config;

class MountEvent {
    //---------------------------- onStart 阶段 ------------------------------------
    
    /**
     * 异步进程服务 
    */ 
    public static function WorkerStart_Task(){
        $config = \houze\Config::get('server');
        if($config['is_task'] && $config['count'] == 1){
            // 异步进程服务
            $task_worker = new \Workerman\Worker('tcp://127.0.0.1:'.\houze\Config::get('server.task_port'));
            // task进程数可以根据需要多开一些
            $task_worker->count = \houze\Config::get('server.task_count') * 10;
            $task_worker->name = 'TaskWorker';
            $task_worker->onConnect = function($connection){};
            $task_worker->onError = function($connection, $code, $msg){};
            $task_worker->onMessage = function($connection, $task_data){
                $class = new \ReflectionClass($task_data);
                $fuc = $class->newInstance();
                // 执行业务逻辑
                $fuc->_callback();
                if(!empty($fuc->result)){
                    // 存储结果
                    $redis = new \houze\Redis();
                    $redis->set('task_result', json_encode($fuc->result));
                    $redis->return();
                    // 返回结果
                    $connection->send(json_encode($fuc->result));
                }
            };
            $task_worker->listen();
        }
    }
    
    /**
     * 心跳定时
    */
    public static function WorkerStart_Heartbeat($server) {
        if (Config::get('heartbeat_is_set')) {
            \Workerman\Timer::add(Config::get('heartbeat_check_interval'), function () use ($server) {
                $time_now = time();
                foreach($server->connections as $connection) {
                    // 有可能该connection还没收到过消息，则lastMessageTime设置为当前时间
                    if (empty($connection->lastMessageTime)) {
                        $connection->lastMessageTime = $time_now;
                        continue;
                    }
                    // 上次通讯时间间隔大于心跳间隔，则认为客户端已经下线，关闭连接
                    if ($time_now - $connection->lastMessageTime > Config::get('server.heartbeat_idle_time')) {
                        $connection->close();
                    }
                }
            });
        }
    }
    
    /**
     * 定时任务挂载
    */
    public static function WorkerStart_Crontab($server, $workerId) {
        // 只有第一个worker进程才能挂载任务，否则会造成重发任务并行
        if ($workerId != 0) return false;
        
        // 是否开启内存定时清理
        $memory_clear = Config::get('app.memory_clear');
        if($memory_clear){
            // 1小时一次
            \Workerman\Timer::add(3600, function () {
                // 清理内存泄露
                gc_mem_caches();
            });
        }

        // 读取定时任务列表
        $crontab_list = Config::get('crontab');
        foreach ($crontab_list as $v) {
            if (isset($v['status']) && $v['status']==false) continue;
            if (!isset($v['use']) || !isset($v['rule'])) continue;

            if (!class_exists($v['use'])) {
                // 此处需要关闭服务，否则worker将一直重启
                \Workerman\Worker::stopAll();
                throw new \houze\exception\CrontabException(SystemTips::CRONTAB_1.$v['use']);
                return false;
            }

            // 载入定时器
            $obj = new $v['use'];
            // 分解规则参数
            $rule = $obj->rule_cutting($v['rule']);
            if (!$rule) {
                unset($obj);
                continue;
            }
            // 写入Workerman实例
            $obj->setServer($server);
            // 写入规则
            $v['rule'] = $rule;
            $obj->setRule($v);
            // 日志文件地址
            $path = LOG_PATH.'crontab'.DS.str_replace('\\', '_', $v['use']).'.log';
            // Linux风格
            if (is_array($rule)) {
                // 1秒一次
                \Workerman\Timer::add(1, function ($timer_id) use ($server, $obj, $v, $path) {
                    // 查看任务是否达到执行时间
                    $status = $obj->task_vif($v['rule']);
                    if ($status) {
                        // 写入任务ID
                        $obj->setTimerId($timer_id);
                        // 开始任务
                        $res = $obj->run();
                        // 记录日志
                        if (isset($v['bin_log']) && $v['bin_log']==true) {
                            $log = date('Y-m-d H:i:s', time()).'，返回值：'.($res ?: '无');
                            file_put_contents($path, $log.PHP_EOL, FILE_APPEND);
                        }
                    }
                });
            // 自定义秒
            } else {
                \Workerman\Timer::add($rule, function ($timer_id) use ($server, $obj, $v, $path) {
                    // 写入任务ID
                    $obj->setTimerId($timer_id);
                    // 开始任务
                    $res = $obj->run();
                    // 记录日志
                    if (isset($v['bin_log']) && $v['bin_log']==true) {
                        $log = date('Y-m-d H:i:s', time()).'，返回值：'.($res ?: '无');
                        file_put_contents($path, $log.PHP_EOL, FILE_APPEND);
                    }
                });
            }
        }

        \houze\StartRecord::crontab();
    }

    /**
     * HTTP-初始化路由表
    */
    public static function WorkerStart_RouteStart_Http() {
        \houze\route\doc\Table::run()->start_http();

        \houze\StartRecord::http_doc_reload();
    }

    /**
     * WebSocket-初始化路由表
    */
    public static function WorkerStart_RouteStart_WebSocket() {
        \houze\route\doc\Table::run()->start_websocket();

        \houze\StartRecord::websocket_doc_reload();
    }

    /**
     * Rpc-初始化路由表
    */
    public static function WorkerStart_RouteStart_Rpc() {
        \houze\route\doc\Table::run()->start_rpc();

        \houze\StartRecord::rpc_doc_reload();
    }

    /**
     * 初始化微服务
    */
    public static function WorkerStart_RpcClient($workerId) {
        // 只有第一个worker进程才能挂载任务，否则会造成重发任务并行
        if ($workerId != 0) return false;

        // 初始化微服务
        if (Config::get('rpc.http_rpc_is') != true) return false;
        
        \houze\Rpc::run()->start();
    }

    /**
     * 打开Mysql连接池
    */
    public static function WorkerStart_MysqlStart() {
        if (Config::get('mysql.driver') == 'mysql') {
            // 启动数据库连接池
            \houze\db\mysql\Pool::run()->init();
        }
    }
    
    /**
     * 打开Redis连接池
    */
    public static function WorkerStart_RedisStart() {
        // 启动数据库连接池
        \houze\redis\Pool::run()->init();
    }

    /**
     * 打开MongoDb连接池
    */
    public static function WorkerStart_MongoDbStart() {
        // 启动数据库连接池
        \houze\mongodb\Pool::run()->init();
    }
    
    /**
     * 打开RabbitMQ连接池
     */
    public static function WorkerStart_RabbitMqStart() {
        // 启动数据库连接池
        \houze\rabbitmq\Pool::run()->init();
    }

    /**
     * 打开Memcache连接池
     */
    public static function WorkerStart_MemcacheStart() {
        // 启动数据库连接池
        \houze\memcached\Pool::run()->init();
    }
    
    /**
     * 路由限流器重置定时任务
    */
    public static function WorkerStart_LimitRouteReset($server, $workerId, $service_type) {
        // 只有第一个worker进程才能挂载任务，否则会造成重发任务并行
        if ($workerId != 0) return false;
        
        $list = \houze\Limit::run()->readRouteTimeAll($service_type);
        foreach ($list as $time => $array) {
            \Workerman\Timer::add($time, function ($timer_id) use ($service_type,$array) {
                foreach ($array as $route => $i) {
                    \houze\Limit::run()->routeAtomicReset($service_type, $route);
                }
            });
        }
    }

    /**
     * IP限流器重置定时任务
    */
    public static function WorkerStart_LimitIpReset($server, $workerId) {
        // 只有第一个worker进程才能挂载任务，否则会造成重发任务并行
        if ($workerId != 0) return false;
        
        $list = \houze\Limit::run()->readIpTimeAll();
        foreach ($list as $time => $array) {
            \Workerman\Timer::add($time, function ($timer_id) use ($array) {
                foreach ($array as $ip => $i) {
                    \houze\Limit::run()->ipAtomicReset($ip);
                }
            });
        }
    }

    /**
     * 自动热重载
    */
    public static function Reload() {
        if (Config::get('reload.status')) {
            \houze\Reload::init();
            \houze\Reload::timer();
        }
    }
    
    /**
     * Elasticsearch嗅探定时器
    */
    public static function ElasticsearchNodeSniff() {
        \houze\elasticsearch\tool\Client::start();
        \houze\elasticsearch\tool\Client::normal_sniff_interval();
        \houze\elasticsearch\tool\Client::fault_sniff_interval();
    }
}